use std::io;
use std::cmp::PartialOrd;

fn main() {
    let mut input = String::new();
    let _  = io::stdin().read_line(&mut input).unwrap();
    let mut parts = input.split_whitespace();
    let m = parts.next().unwrap().parse::<usize>().unwrap();
    let n = parts.next().unwrap().parse::<usize>().unwrap();
    let mut a: Vec<Vec<usize>> = vec![vec![0; n+1]; m+1];
    let mut b: Vec<Vec<i32>> = vec![vec![0; n+1]; m+1];
    // 初始化
    for row in &mut a {
        row.fill(0);
    }
    for row in &mut b {
        row.fill(0);
    }
    // 输入
    for i in 1..m+1 {
        input.clear();
        let _ = io::stdin().read_line(&mut input).unwrap();
        for (j, value) in input.trim().split_whitespace().map(|x| x.parse::<usize>().unwrap()).enumerate() {
            a[i][j+1] = value;
        }
        for j in 1..n {
            b[i][j] = b[i-1][j] + b[i][j-1] - b[i-1][j-1] + a[i][j] as i32;
        }
    }
    let mut l: usize = 1;
    let mut ans: i32 = 1;
    while l<min(m, n) {
        for i in l..m+1 {
            for j in l..n+1 {
                // print!("{} ", j);
                if b[i][j] - b[i-l as usize][j] - b[i][j-l] + b[i-l][j-l] == (l*l) as i32 {
                    ans = max(ans, l as i32);
                }
            }
            // println!("");
        }
        // println!("");
        l = l + 1;
    }
    println!("{}", ans)
    
}

fn min<T: PartialOrd>(m: T, n: T) -> T{
    let res = if m<n {m} else {n};
    res
}
fn max<T: PartialOrd>(m: T, n: T ) -> T {
    let res = if m<n {n} else {m};
    res
}